package edu.gatech.volt2.drdoommgt.domain;



import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.swing.JOptionPane;

import edu.gatech.volt2.drdoommgt.exceptions.LoginException;
import edu.gatech.volt2.drdoommgt.system.DataBaseAccessor;

import java.util.Map;
import java.util.logging.*;

/**
 * This class serve as the log in manager for the user.
 * 
 * @author Perron Jones
 *
 */
public class Login {

	@SuppressWarnings("unused")

	private String correctPassword;
	
	private static Logger myLogger = Logger.getLogger("edu.gatech.volt2.drdoommgt.domain.Login");
		
    static 
    {
        FileHandler fh = null;
        try {
            fh = new FileHandler("application.log");
        } catch (SecurityException e) {
            myLogger.log(Level.SEVERE, "Security Exception creating the logger file handler", e);
            e.printStackTrace();
        } catch (IOException e) {
            myLogger.log(Level.SEVERE, "IO Exception creating the logger file handler", e);
            e.printStackTrace();
        }
        
        fh.setFilter( new Filter() {
            public boolean isLoggable(LogRecord record) {
                //we would put whatever logic we need in here to 
                //determine if this should be logged.
                //for demo purposes, I am putting true
                return true;
            }
        });
        myLogger.addHandler(fh);
        myLogger.setLevel(Level.ALL);
    }
	
    /**
     * This is a default constructor for the log in class
     */
	public Login()
	{
		//nothing happens
	}
	
	/**
	 * This constructor takes in a User object and sets the correct password for login issues
	 */
	public Login(User user)
	{
		this.correctPassword= user.getPassword();
	}
	
	
	public static Map<UserType, User> loginProcess(DataBaseAccessor db, String email, String pass) throws LoginException{
		String password = encryptPassword(pass);

		Map<UserType, User> foundUserMap = db.findUnknownByEmail(email);
		UserType type = (UserType) foundUserMap.keySet().toArray()[0];
		User foundUser = foundUserMap.get(type);
		if ( foundUser.isSuspended() ){
			throw new LoginException("User suspended");
		}
		else if ( !foundUser.getPassword().equals(password) ){
			throw new LoginException("Incorrect Password");
		}else{
			return foundUserMap;
		}
	}
	
	
	/**
	 * This method performs the login process where the user attempts to log into the system.
	 * 
	 * @param user the user that is attempting to log in
	 * @return the modified user (may have a new loggedIn or suspended value)
	 */
	public User loginProcess(User user)
	{
		if(user != null)
		{
			if(!user.isSuspended())
			{
				if(!user.isLoggedIn())
				{
					this.attemptLogin(user);
				}
				else
				{
					myLogger.log(Level.WARNING, "User is already logged in");
				}
			}
			else
			{
				myLogger.log(Level.WARNING, "User is suspended");
			}
		}
		else
		{
			myLogger.log(Level.WARNING, "User is not existing");
		}

		//return user to store user object back into the database
		return user;
			
	}
	
	/**
	 * This method performs the login process where the user attempts to log into the system.
	 * This method is for the presenter. That is why is also takes in a password attempt
	 * string.
	 * 
	 * @param user the user that is attempting to log in
	 * @return the modified user (may have a new loggedIn or suspended value)
	 */
	public User loginProcess(User user, String passwordAttempt)
	{
		if(user != null)
		{
			if(!user.isSuspended())
			{
				if(!user.isLoggedIn())
				{
					this.attemptLogin(user, passwordAttempt);
				}
				else
				{
					myLogger.log(Level.WARNING, "User is already logged in");
				}
			}
			else
			{
				myLogger.log(Level.WARNING, "User is suspended");
			}
		}
		else
		{
			myLogger.log(Level.WARNING, "User is not existing");
		}

		//return user to store user object back into the database
		return user;
			
	}
	
	/**
	 * This is actual method that controls the log in processes from the user
	 * 
	 * @param user the user attempting to log in
	 */
	private void attemptLogin(User user)
	{
		int counter= 0;
		boolean quit= false;
		//Scanner scanPassword= new Scanner(System.in);
		String tryAgain= "";
		String passwordAttempt= "";
		while(counter < 3 && !quit)
		{
			//System.out.println("Enter Password");
			passwordAttempt= JOptionPane.showInputDialog("Enter password");
			//passwordAttempt= "Yessir"; //used ONLY for testing purposes. Will be deleted
			passwordAttempt= this.encryptPassword(passwordAttempt);			
			
			if(passwordAttempt.equals(this.correctPassword))
			{
				quit= true;
				user.setLoggedIn(true);
				System.out.println("You are now logged in.");
				myLogger.log(Level.INFO, "User is now logged in.");
				
			}
			else
			{
				myLogger.log(Level.WARNING, "Wrong password entered");
				counter++;
				tryAgain= JOptionPane.showInputDialog("Wrong password entered?\nWould you like to attempt again?",JOptionPane.YES_NO_OPTION);
				
				JOptionPane.showConfirmDialog(null, "choose one", "choose one", JOptionPane.YES_NO_OPTION);
				if(tryAgain.equalsIgnoreCase("no"))
				{
					quit= true;
					user.setLoggedIn(false);
					myLogger.log(Level.INFO, "User has not been logged in.");
				}
			}
		}//end while
		
		if(counter >= 3)
		{
			this.suspend(user);
			myLogger.log(Level.WARNING, "User has been suspended. Must wait until a system administrator unsuspends.");
		}
	}
	
	/**
	 * This is actual method that controls the log in processes from the user
	 * This method is for the presenter. That is why is also takes in a password attempt
	 * string.
	 * 
	 * @param user the user attempting to log in
	 */
	private void attemptLogin(User user, String passwordAttempt)
	{
		int counter= 1;
		boolean quit= false;
		int tryAgain= 0;
		while(counter < 3 && !quit)
		{
			//passwordAttempt= JOptionPane.showInputDialog("Enter password");
			//passwordAttempt= "Yessir"; //used ONLY for JUnit test purpose. Will be deleted
			passwordAttempt= this.encryptPassword(passwordAttempt);			
			
			if(passwordAttempt.equals(this.correctPassword))
			{
				quit= true;
				user.setLoggedIn(true);
				System.out.println("You are now logged in.");
				myLogger.log(Level.INFO, "User is now logged in.");
				
			}
			else
			{
				myLogger.log(Level.WARNING, "Wrong password entered");
				counter++;
				//tryAgain= JOptionPane.showInputDialog("Wrong password entered?\nWould you like to attempt again?"); //only used for testing. Will be deleted.
				tryAgain= JOptionPane.showConfirmDialog(null, "Wrong password entered?\nWould you like to attempt again?", "Incorrect password", JOptionPane.YES_NO_OPTION); //0-yes, 1-no
				if(tryAgain==1)
				{
					quit= true;
					user.setLoggedIn(false);
					myLogger.log(Level.INFO, "User has not been logged in.");
				}
				else
				{
					passwordAttempt= JOptionPane.showInputDialog("Enter password. Attempt " + Integer.toString(counter));
				}
			}
		}//end while
		
		if(counter >= 3)
		{
			this.suspend(user);
			myLogger.log(Level.WARNING, "User has been suspended. Must wait until a system administrator unsuspends.");
		}
	}
	
	/**
	 * This method suspends the user
	 * 
	 * @param user the user to be suspended
	 */
	private void suspend(User user)
	{
		//get changed loggedIn and suspended for the corresponding user
		user.setLoggedIn(false);
		user.setSuspended(true);
	}
	
	/**
	 * This method encryptes the attempted password to match the attempted password with
	 * the password in the database.
	 */
	public static String encryptPassword(String password)
	{	
		MessageDigest messageDigest = null;
		try {
			messageDigest = MessageDigest.getInstance("SHA-256");
			
			messageDigest.update(password.getBytes());
			 
	        byte byteData[] = messageDigest.digest();
	 
	        //convert the byte returned from the hash method into a string
	        StringBuffer sb = new StringBuffer();
	        for (int i = 0; i < byteData.length; i++) {
	         sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
	        }
	        password = sb.toString();
	        
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
            myLogger.log(Level.SEVERE, "IO Exception creating the logger file handler", e);
            //password = password;
			System.err.println("No such Algorithm 'SHA-256' in User.setPassword()");
		}
		
		return password;
	}
	
	
	/**
	 * @param password the correct email to set
	 */
	private void setCorrectPassword(String password)
	{
		this.correctPassword= password;
	}
	
}
